home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODF-Interest Archive / March 96 / Re Initializing an Extension.2 < prev    next >
Encoding:
Internet Message Format  |  1996-12-03  |  7.9 KB  |  [TEXT/ttxt]

  1. Subject:     Re: Initializing an Extension
  2. Sent:        3/9/96 10:21 AM
  3. Received:    3/11/96 8:27 AM
  4. From:        Greg Friedman, friedman@cognosis.com
  5. Reply-To:    ODF-Interest@CILabs.ORG
  6. To:          OpenDoc Development Framework Discussion List, ODF-Interest@CILabs.
  7.  
  8. Bernhard asked:
  9.  
  10. >
  11. >Why would you want to register the part with the
  12. >extension via its init method?  Shouldn't it be the other way around?
  13. >The part registers the extension.  If the part wants to get access to it, it
  14. >calls GetExtensionManager( /* no ev in D11 Damon */ )->AcquireExtension(
  15. >ev, kMyExtName )?
  16.  
  17. There are two objects involved in an extension transaction: the ODObject
  18. that owns and creates the extension, and the ODObject that requests and
  19. acquires the extension. Note that I say ODObject, not ODPart, since the
  20. extension API is introduced in ODObject, from which ODPart derives. The
  21. interactions and responsibilities, described from the perspective of the
  22. owning object, are as follows:
  23.  
  24. Owning ODObject (assume a part developed in ODF):
  25.  
  26. At startup, register the extension's creation function with the extension
  27. manager. (In ODF d11, the registration function takes only a function
  28. pointer as a parameter. In ODF 1, we've added a reference constant and a
  29. boolean indicating whether the extension should be cached by the extension
  30. manager when its reference count drops to zero. This latter parameter was
  31. added to reduce the overhead of accessing extensions such as the semantic
  32. interface which are required and released frequently. Many extensions will
  33. be acquired once and released once. Caching won't apply in these cases.)
  34.  
  35. When a client is interested in the availability of a specific extension, it
  36. calls the HasExtension method of the owning part. HasExtension is
  37. encapsulated in the extension manager: it returns TRUE if an extension with
  38. the specified name has been registered, and FALSE if it hasn't.
  39.  
  40. When a client wants to acquire the extension, it calls the AcquireExtension
  41. method of the owning part. The extension manager looks for an existing
  42. extension with the specified name. If it finds one, it increments the
  43. reference count by calling extension::Acquire, and returns the extension.
  44. If it doesn't find one, it looks for a creation function that maps to the
  45. specified name. If it finds on, it calls it.
  46.  
  47. The creation function creates, initializes, and returns an instance of the
  48. requested extension. This should always involve calling an Init method
  49. defined by the extension. I believe this is the method you are asking
  50. about, so I'll go into a little bit of detail.
  51.  
  52. The function of an extension is to extend the API of the object that owns
  53. it. If you have, for example, a part that can perform spell checking on
  54. text runs it displays in its own frames, you may decide to make the spell
  55. checking service available to other parts. This would require the
  56. introduction of new API to some object that other parts can get access to.
  57. One way to do this would be to create an extension that has methods
  58. BeginSpellingSession, FindNextError, ReplaceAndContinue, GetStatistics,
  59. EndSpellingSession, etc. You might decide to introduce this API by
  60. declaring a new extension type. Clients who want to use the service can
  61. then ask parts in their document whether or not they have the extension
  62. and, if they find one that does, they can acquire it at need.
  63.  
  64. The spell checking functionality is implemented in the part that owns the
  65. spelling extension. The extension is just API that calls into the part to
  66. get the work done. This makes the sense when you remember that an extension
  67. "extends the API" of the object that owns it. This is why you provide a
  68. back pointer to the owning object when you create an extension: so the
  69. extension can call into the owning object.
  70.  
  71. The object that created and owns the extension is called the "base" object.
  72. It is important to remember, when writing an extension, that an extension's
  73. base might go away while some client of the extension still has a reference
  74. to an active extension. An example: In the spell checking example above,
  75. some part acquires and keeps a spell checking extension. The user decides
  76. to delete the spell checking part from the document. The spell checking
  77. part, having been developed using ODF 1, correctly implements the extension
  78. recipe, and calls the "BaseRemoved" method of the spelling extension that
  79. it provided. The spelling part is then destroyed, but the extension is not.
  80. Now, whenever the spelling extension is called, it cannot call into its
  81. base, since the base no longer exists. The correct implementation for this
  82. behavior is for an extension to call IsValid before attempting to call into
  83. its base object. IsValid will return FALSE if the extension's base has been
  84. removed.
  85.  
  86. Moving on to the rest of the extension protocol:
  87.  
  88. When a client is done with an extension, it calls the Release method of the
  89. extension (* Not the ReleaseExtension method of the part that provided the
  90. extension *). This is an important point: extensions are acquired from the
  91. objects that own them. They are released directly, not through their owner.
  92. This is particularly important given the above description of how a part
  93. might go away before its extensions have been released.
  94.  
  95. When an extension is released it should call its inherited
  96. ODExtension::Release method. This method decrements the reference count of
  97. the extension. If the reference count has dropped to zero, and the base has
  98. not been removed, the base object's ReleaseExtension method is called. It
  99. does not handle the case where the reference count has dropped to zero, but
  100. the base has been removed. In your extension, you should override release
  101. and do something like the following:
  102.  
  103.  
  104. FW_Boolean isValid = somSelf->IsValid(ev);
  105.  
  106. FW_OSemanticInterface_parent_ODSemanticInterface_Release(somSelf,ev);
  107.  
  108. if (!isValid && somSelf->GetRefCount(ev) == 0)
  109.      delete somSelf;
  110.  
  111. The call to IsValid is made before calling the parent method, because the
  112. parent method might cause the extension to be destroyed if the reference
  113. count drops to zero and the base is valid. My experience suggests that it
  114. is not always a good idea to use an object pointer after the object has
  115. been destroyed.
  116.  
  117. In your question, you suggest that if a part wants to get to an extension
  118. that it owns, it should call its own AcquireExtension method. This is
  119. correct. To facilitate this, we've extended the internal AcquireExtension
  120. API by adding a boolean to the method indicating whether or not the
  121. extension manager should create an instance of the extension if one doesn't
  122. exist. This means that it will be possible to acquire the extension if and
  123. only if it already exists. This is useful for our internal implementation
  124. of a semantic interface. It may or may not apply ot the work you are doing.
  125. Since the parameter is part of the internal API, it is not available to
  126. external extension clients.
  127.  
  128. I hope this addresses your questions. If not, I'll try to provide more
  129. specific information about the areas you find confusing.
  130.  
  131. >p.s.  "Every SOM call can produce a SOM Exception."  I am worried that
  132. >SOM error checking is not consistently apparent.  Do I have reason to be?
  133.  
  134. Jim already addressed this, but I'll add a couple of comments. Whenever you
  135. call from ODF into SOM, the possibility exists that a som error returned
  136. through the ODF/SOM boundary will converted to an ODF exception and will be
  137. rethrown. The danger here is that it is fatal to allow the ODF exception to
  138. propogate back out into SOM. This means that you should protect all of your
  139. extensions SOM entry points with try/catch blocks that guarantee that an
  140. ODF exception won't make it back out into SOM. Your entry points should
  141. look something like:
  142.  
  143. FW_TRY
  144. {
  145.    ... do your thing
  146. }
  147. FW_CATCH_BEGIN
  148. FW_CATCH_REFERENCE(FW_XException, exception)
  149. {
  150.      FW_SetException(ev, exception);
  151. }
  152. FW_CATCH_EVERYTHING()
  153. {
  154.      FW_SetEvError(ev, kODErrUndefined);
  155. }
  156. FW_CATCH_END
  157.  
  158. I hope this helps,
  159.  
  160. gsf.
  161.  
  162.  
  163. ___________________________________________________________
  164. Greg Friedman        ODF Engineering         Apple Computer
  165.  
  166.